package com.tom.aop.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Parameter;
import java.util.Objects;

@Slf4j
@Aspect
@Component
public class ControllerLogAdvice {
    private final ThreadLocal<Long> recordTime = new ThreadLocal<>();
		
  	// @Pointcut("execution( * com.tom.service.*.*(..))")
    // 这个包下的所有类的所有方法
    @Pointcut("@within(org.springframework.stereotype.Controller) || @within(org.springframework.web.bind.annotation.RestController)")
    public void pointcut() {
    }


    /**
     * 方法执行前
     */
    @Before("pointcut()")
    public void handle(JoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        recordTime.set(System.currentTimeMillis());
        // LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
        log.info("请求url:{},请求方式:{},访问的方法名:{},当前访问的class类及类名:{},入参: {}",
                request.getRequestURI(),
                request.getMethod(),
                joinPoint.getSignature().getName(),
                joinPoint.getTarget().getClass().getCanonicalName(),
                getRequestParam(joinPoint));
    }

    /**
     * 后置通知
     */
    @AfterReturning(returning = "ret", pointcut = "pointcut()")
    public void doAfterReturning(Object ret) {
        try {
            Long time = System.currentTimeMillis() - recordTime.get();
            // 处理完请求，返回内容
            log.info("响应:{},耗时:{}ms", JSONObject.toJSONString(ret), time);
        } finally {
            recordTime.remove();
        }
    }


    /**
     * 获取请求参数
     */
    private String getRequestParam(JoinPoint point) {
        Object[] methodArgs = point.getArgs();
        Parameter[] parameters = ((MethodSignature) point.getSignature()).getMethod().getParameters();
        String requestStr;
        try {
            requestStr = logParam(parameters, methodArgs);
        } catch (Exception e) {
            requestStr = "获取参数失败";
        }
        return requestStr;
    }

    /**
     * 拼接请求参数
     */
    private String logParam(Parameter[] paramsArgsName, Object[] paramsArgsValue) {
        if (ArrayUtils.isEmpty(paramsArgsName) || ArrayUtils.isEmpty(paramsArgsValue)) {
            return "";
        }
        StringBuilder buffer = new StringBuilder();
        for (int i = 0; i < paramsArgsValue.length; i++) {
            // 参数名
            String name = paramsArgsName[i].getName();
            // 参数值
            Object value = paramsArgsValue[i];
            buffer.append(name).append("=");
            if (value instanceof String) {
                buffer.append(value).append(",");
            } else {
                buffer.append(JSON.toJSONString(value)).append(",");
            }
        }
        return buffer.toString();
    }
}
